public virtual class AtomBase {
	private List<Person> author = new List<Person>();
	private List<Category> category = new List<Category>(); 
  	private Content content;
  	private List<Person> contributor = new List<Person>();
  	private List<Link> link = new List<Link>();
  	private AtomDateTime published;
  	private Text rights;
  	private Source source; 
  	private Text summary;
  	private Text title;
  	private AtomDateTime updated;
  	private AtomDateTime edited;
  	private Boolean isDraft;
  	private String id;

	protected Map<String, String> namespaces;
	private final String XHTML_DIV = '<div xmlns="http://www.w3.org/1999/xhtml">';
	private final String XHTML_CLOSE_DIV = '</div>';
	
	public Map<String, Element> extensions;

	private AtomBase child;
	
	public AtomBase() {
		initCollections();
		namespaces.put('xmlns', 'http://www.w3.org/2005/Atom'); 
	}
	public AtomBase(String title) { this(); }

	public void appendChild(AtomBase child) {
		this.child = child;
	}
	
	public AtomBase getChild() {
		return child;
	}

	public String output = '';
	
	public AtomBase(XmlStreamReader reader) {
		String nodeName;
		String nodeText;
		initCollections();
		
		while (reader.hasNext()) {
	        if (reader.getEventType() == XmlTag.START_ELEMENT) {
				nodeName = reader.getLocalName();
				nodeText = '';
				try {
					if (nodeName == 'author') { 
		   				System.debug(LoggingLevel.FINE, addAuthor(new Person(reader, nodeName)).toAPP()); 
					} else if (nodeName == 'category') { 
						System.debug(LoggingLevel.FINE, addCategory(new Category(reader)).toAPP());
					} else if (nodeName == 'link') {
						System.debug(LoggingLevel.FINE, addLink(new Link(reader)).toAPP());
					} else if (nodename == 'contributor') {
						System.debug(LoggingLevel.FINE, addContributor(new Person(reader, nodeName)).toAPP());
					} else if (nodeName == 'source') {
						System.debug(LoggingLevel.FINE, setSource(new Source(reader)).toAPP());
					} else if (nodeName == 'content') {
						System.debug(LoggingLevel.FINE, setContent(new Content(reader)).toAPP());
					} else if (nodeName == 'entry' || nodeName == 'id' || nodeName == 'title' || nodeName == 'summary' ||
					 				nodeName == 'rights' || nodeName == 'published' || nodeName == 'updated' || 
					 				nodeName == 'edited' || nodeName == 'isDraft') {
					 	System.debug(LoggingLevel.FINE, 'Skipping...' + nodeName);
						System.debug(LoggingLevel.INFO, '\n\n\t AtomBase: Skipping start element ' + nodeName + '\n');
					} else if (reader.getPrefix() != null && reader.getPrefix() != '') {
						System.debug(LoggingLevel.FINE, 'Extension...' + nodeName);
						System.debug(LoggingLevel.INFO, '\n\nCreating extensions for ' + reader.getLocalName().toUpperCase() + '\n');
						extensions.put(reader.getLocalName(), new Element(reader));
					} else {
						handleStartTag(reader, nodeName);
						System.debug(LoggingLevel.INFO, '\n\n\t AtomBase: breaking out of loop at ' + nodeName + '\n');
						break;
					}
				} catch (Exception e) {
					System.debug(LoggingLevel.ERROR, '\n\nSTART_ELEMENT Error parsing entry node...\ntagname: ' + nodeName + '\ntag value: ' + nodeText + '\nMessage: ' + e.getMessage() + '\n');
				}
			} else if (reader.getEventType() == XmlTag.CHARACTERS) {
				if ( ! reader.isWhitespace()) { 
                    nodeText += reader.getText();  // add text to current element
                }
	        } else if (reader.getEventType() == XmlTag.END_ELEMENT) {
				try {
					System.debug(LoggingLevel.FINE, 'End Element: ' + nodeName + '');
					System.debug(LoggingLevel.INFO, '\n\n\t AtomBase: closing tag for element ' + nodeName + ':' + nodeText + '\n');
					if (nodeName == 'rights') { 
						System.debug(LoggingLevel.FINE, setRights(nodeText).toAPP());
					} else if (nodeName == 'summary') {
						System.debug(LoggingLevel.FINE, setSummary(nodeText).toAPP());
					} else if (nodeName == 'title') {
						System.debug(LoggingLevel.FINE, setTitle(nodeText).toAPP());
					} else if (nodeName == 'published') {
						setPublished(Datetime.valueOf(nodeText.replaceAll('T', ' ')));
						System.debug(LoggingLevel.FINE, getPublishedElement());
					} else if (nodename == 'updated') {
						setUpdated( Datetime.valueOf(nodeText.replaceAll('T', ' ')));
						System.debug(LoggingLevel.FINE, getUpdatedElement());
					} else if (nodeName == 'edited') {
						setEdited( Datetime.valueOf(nodeText.replaceAll('T', ' ')));
						System.debug(LoggingLevel.FINE, getUpdatedElement());
					} else if (nodeName == 'isDraft') {
						setIsDraft( Boolean.valueOf(nodeText));
						System.debug(LoggingLevel.FINE, getIsDraftElement());
					} else if (nodeName == 'id') {
						setId(nodeText);
						System.debug(LoggingLevel.FINE, getIdElement());
					} else if (reader.getLocalName() == 'entry') {
						System.debug(LoggingLevel.INFO, '\n\n\t AtomBase: returning from constructor...\n');
		   				return;
		   			} else { 
		   				//ParseExtensionEndTag(reader, nodeText);
					}
				} catch (Exception ex) {
					System.debug(LoggingLevel.ERROR, '\n\nEND_ELEMENT Error parsing entry node...\ntagname: ' + nodeName + '\ntag value: ' + nodeText + '\n' + ex.getMessage() + '\n');
				}
	        }
	        reader.next();
		}
	}

	public void clone(AtomBase other) {
		other.setAuthors(getauthors()); 
		other.setCategories(getCategories()); 
  		other.setContent(getContent()); 
  		other.setContributors(getContributors());
	  	other.setLinks(getLinks());
	  	other.setPublished(getPublished());
	  	other.setRights(getRights()); 
	  	other.setSource(getSource());
	  	other.setSummary(getSummary());
	  	other.setTitle(getTitle());
	  	other.setUpdated(getUpdated());
	  	other.setEdited(getEdited());
	  	other.setIsDraft(getIsDraft());
	  	other.setId(getId());
	}
	
	protected void initCollections() {
		author = new List<Person>();
		category = new List<Category>();
		contributor = new List<Person>();
		link = new List<Link>();
		namespaces = new Map<String, String>();
		extensions = new Map<String, Element>();
		InitExtensionCollections();
	}
	
	public String dump() {
		String output = '';
		output += 'Author: \n';
		for (Person p : author) {
			output += p.ToApp() + '\n';
		}
		output += 'Extensions: \n';
		for (String key : extensions.keySet()) {
			output += '<snx:' + key + '>' + extensions.get(key) + '</snx:' + key + '>\n';
		}
		return output;
	}
	
	public virtual void InitExtensionCollections() {
	}
	
	protected virtual void handleStartTag(XmlStreamReader reader, String nodeName) {
		System.debug(LoggingLevel.WARN, '\n\nHandling the start tag in the AtomBase...' + nodeName + '\n');
	}
	public virtual void ParseExtensionStartTag(XmlStreamReader reader, String nodeName) {
	
	}
	public virtual void ParseExtensionCharacters(XmlStreamReader reader) {
		
	}
	public virtual void ParseExtensionEndTag(XmlStreamReader reader, String nodeText) {
		
	}
	public virtual String ToAPP() {
		String out = '<entry ';
		if (namespaces.size() > 0) {
			for (String key : namespaces.keySet()) {
				out += key + '="' + namespaces.get(key) + '" ';
			}
		}
		out += '>';
		out += ChildrenToAPP();
		out += ExtensionsToAPP();
		out += '</entry>';
		return out;
	}
	public virtual String ChildrenToAPP() {
		String out = '';
		out += getAuthorElement();
		out += getCategoryElement();
		out += getContentElement();
		out += getContributorElement();
		out += getLinkElement();
		out += getRightsElement();
		out += getSourceElement();
		out += getSummaryElement(); 
		out += getTitleElement();
		out += getIsDraftElement();
		//out += getCollectionElement();
		return out;
	}
	
	public virtual String ExtensionsToAPP() {
		String out = '';
		for (String key : extensions.keySet()) {
			out += '<' + key + '>' + extensions.get(key).value + '</' + key + '>\n';
		}
		return out;
	}
	
	public AtomBase(String id, List<String> authors, String content, List<String> contributors,
			Datetime published, List<String> tags, String title, Datetime updated, String link) {
		this.id = id;
		for (String author : authors) {
			addAuthor(author);
		}
		setContent(content);
		for (String contributor : contributors) {
			addContributor(contributor);
		}
		setPublished(published);
		for (String tag : tags) {
			//addCategory(tag);
		}
		//setTitle(title);
		setUpdated(updated);
		addLink(link);
	}
	
	public Person getAuthor() {
  		if (author != null && author.size() > 0) {
  			return author[0];
  		} else {
  			return null;
  		}
  	}
	public List<Person> getAuthors() {
  		return author;
	}
  
  	public void setAuthors(List<Person> a) {
  		author = a;
  	}
  	
  	public String getAuthorElement() {
  		String out = '';
  		if (author == null || author.size() == 0) {
  			return out;
  		} else {
  			for (Person p : author) {
  				out += p.ToAPP();
  			}
  			return out;
  		}
  	}
  	
	public AtomBase addAuthor(Person person) {
  		author.add(person);
  		return this;
	}
  
	public Person addAuthor(String name) {
		Person p = new Person();
		p.name = name;
		addAuthor(p);
		return p;
 	}
  
	public Person addAuthor(String name, String email, String uri) {
  		Person p = addAuthor(name);
  		p.email = email;
  		p.uri = uri;
  		return p;
  	} 
  
  	public List<Category> getCategories() {
  		return category;
  	}
  
  	public List<Category> getCategories(String scheme) {
  		List<Category> cats = new List<Category>();
  		for (Category c : this.category) {
  			if (c.scheme == scheme) {
  				cats.add(c);
  			}
  		}
  		return cats;
  	}
  	
  	public String getCategoryElement() {
  		String out = '';
  		if (category != null && category.size() > 0) {
  			for (Category c : category) {
  				out += c.ToAPP();
  			}
  		}
  		return out;
  	}
  	
  	public void setCategories(List<Category> c) {
  		category = c;
  	}
  	
  	public AtomBase addCategory(Category category) {
  		this.category.add(category);
  		return this;
  	}
  	
  	public Category addCategory(String term) {
  		Category c = new Category();
  		c.term = term;
  		addCategory(c);
  		return c;
  	}
  	
  	public Category addCategory(String scheme, String term, String label) {
  		Category c = addCategory(term);
  		c.scheme = scheme;
  		c.label = label;
  		return c;
  	}
  	
  	public String getContentElement() {
  		return content != null ? content.ToAPP() : '';
  	}
  
  	public AtomBase setContentElement(Content content) {
  		this.content = content;
  		return this;
  	}
  	
  	public Content setContent(Content theContent) {
  		content = theContent;
  		return content;
  	}
  	
  	public Content setContent(String value) {
  		content = new Content();
  		content.theContent.setValue(value);
  		content.ctype = 'text';
  		return content;
  	}
  	
  	public Content setContentAsHtml(String value) {
  		content = new Content();
  		content.theContent.setValue(EncodingUtil.URLEncode(value, 'UTF-8'));
  		content.ctype = 'html';
  		return content;
  	}
	 
	public Content setContentAsXhtml(String value) {
		content = new Content();
		content.theContent.setValue(XHTML_DIV + value + XHTML_CLOSE_DIV);
		content.ctype = 'xhtml';
		return content;
	}
	
  	public Content setContent(String value, String atype) {
  		System.assert(atype == 'text' || atype == 'html' || atype == 'xhtml', '\n\nContent must be type "text", "html" or "xhtml".\n\n');
  		if (atype == 'text') {
  			setContent(value);
  		} else if (atype == 'html') {
  			setContentAsHtml(value);
  		} else if (atype == 'xhtml') {
  			setContentAsXhtml(value);
  		}
  		return content;
  	}
  //Content setContent(Element value);  
  //Content setContent(Element element, String mediaType);
  //Content setContent(DataHandler dataHandler);
  //Content setContent(DataHandler dataHandler, String mediatype);
  //Content setContent(InputStream inputStream);
  //Content setContent(InputStream inputStream, String mediatype);
  //Content setContent(String value, String mediatype);
  	public Content setContent(URI uri, String mediatype) {
  		content = new Content();
  		content.src = uri;
  		content.mediaType = mediatype;
  		return content;
  	}
  	
  	public Content getContent() {
  		if (content != null ) {
	  		return content;
  		} else {
  			return null;
  		}
  	}
  //InputStream getContentStream() throws IOException;
  	public String getContentSrc() {
  		if (content != null && content.src != null) {
	  		return content.src.url;
  		} else {
  			return null;
  		}
  	}
  	
  	public String getContentType() {
  		return content.ctype;
  	}
  //MimeType getContentMimeType();
  	public List<Person> getContributors() {
  		return contributor;
  	}
  	
  	public String getContributorElement() {
  		String out = '';
  		if (contributor != null && contributor.size() > 0) {
  			for (Person p : contributor) {
  				out += p.ToAPP();
  			}
  		}
  		return out;
  	}
  
  	public void setContributors(List<Person> c) {
  		contributor = c;
  	}
  	
  	public AtomBase addContributor(Person person) {
  		contributor.add(person);
  		return this;
  	}
  	
  	public Person addContributor(String name) {
  		Person p = new Person();
  		p.name = name;
  		addContributor(p);
  		return p;
  	}
  	
	public Person addContributor(String name, String email, String uri) {
		Person p = addContributor(name);
		p.email = email;
		p.uri = uri;
		return p;
	}
	
  /**
   * Returns the universally unique identifier for this entry
   * @return The atom:id element
   */
  //IRIElement getIdElement();
  
  /**
   * Sets the universally unique identifier for this entry
   * @param id The atom:id element
   */
	public AtomBase setIdElement(String id) {
		this.id = id;
		return this;
	}
  
  /**
   * Returns the universally unique identifier for this entry
   * @throws IRISyntaxException  if the atom:id value is malformed
   */
  	public String getId() {
  		return id;
  	}

	public String getIdElement() {
		return '<id>' + id + '</id>';
	}
	
	public String getUsableId() {
		String[] vals = id.split(':');
		return vals[vals.size() - 1];
	}
	
  /**
   * Sets the universally unique identifier for this entry
   * @param id The atom:id value
   * @return The newly created atom:id element
   * @throws IRISyntaxException  if the atom:id value is malformed
   */
  	public String setId(String id) {
  		this.id = id;
  		return id;
  	}
  
  /**
   * Creates a new randomized atom:id for the entry
   */
  //IRIElement newId() ;
  
  /**
   * Sets the universally unique identifier for this entry
   * @param id The atom:id value
   * @param normalize true if the atom:id value should be normalized as called for by RFC4287
   * @return The newly created atom:id element
   * @throws IRISyntaxException if the atom:id value is malformed
   */
  //IRIElement setId(String id, boolean normalize) ;
  
  	public List<Link> getLinks() {
  		return link;
  	}
  	
  	public List<Link> getLinks(String rel) {
  		List<Link> links = new List<Link>();
  		for (Link l : link) {
  			if (l.rel == rel) {
  				links.add(l);
  			}
  		}
  		return links;
  	}
  	
  	public List<Link> getLinks(List<String> rels) {
  		List<Link> links = new List<Link>();
  		for (Link l : link) {
  			String lrel = l.rel;
  			for (String r : rels) {
  				if (r == lrel) {
  					links.add(l);
  					break;
  				}
  			}
  		}
  		return links;
  	}
  	
  	public String getLinkElement() {
  		String out = '';
  		if (link != null && link.size() > 0) {
  			for (Link l : link) {
  				out += l.ToAPP();
  			}
  		}
  		return out;
  	}
  	
  	public void setLinks(List<Link> l) {
  		link = l;
  	}
  	
	public AtomBase addLink(Link link) {
		this.link.add(link);
		return this;
	}
	
	public Link addLink(String href) {
		Link l = new Link();
		l.href = href;
		addLink(l);
		return l;
	}
	
	public Link addLink(String href, String rel) {
		Link l = addLink(href);
		l.rel = rel;
		return l;
	}
  
  /**
   * Add a link to the entry
   * @param href The IRI of the link
   * @param rel The link rel attribute
   * @param type The media type of the link
   * @param hreflang The language of the target 
   * @param length The length of the resource
   * @return The newly created atom:link
   * @throws IRISyntaxException if the href is malformed
   */  
	public Link addLink(String href, String rel, String ltype, String title, String hreflang, String length) {
		Link l = addLink(href, rel);
		l.ltype = ltype;
		l.title = title;
		l.hreflang = hreflang;
		l.length = length;
		return l;
	}
  
  	public void addNamespace(String ns, String uri) {
  		namespaces.put(ns, uri);
  	}
  /**
   * RFC4287: The "atom:published" element is a Date construct indicating an
   * instant in time associated with an event early in the life cycle of
   * the entry... Typically, atom:published will be associated with the initial
   * creation or first availability of the resource.
   * @return The atom:published element
   */
	public String getPublishedElement() {
		return '<published>' + published.getAtomString() + '</published>';
	}
  
  /**
   * RFC4287: The "atom:published" element is a Date construct indicating an
   * instant in time associated with an event early in the life cycle of
   * the entry... Typically, atom:published will be associated with the initial
   * creation or first availability of the resource.
   * @param dateTime the atom:published element
   */
	//public AtomBase setPublishedElement(AtomDateTime adateTime) {
	//	published = adateTime;
	//	return this;
	//}
	
  	public AtomDateTime getPublished() {
  		return published;
  	}
  	
  	public AtomDateTime setPublished(DateTime value) {
  		published = new AtomDateTime(value);
  		return published;
  	}
  	
  	public AtomDateTime setPublished(String value) {
  		published = new AtomDateTime(value);
  		return published;
  	}
  	
  	public void setPublished(AtomDateTime value) {
  		published = value;
  	}

	public String getRightsElement() {
		return rights != null ? rights.ToApp() : '';
	}
	
  	public AtomBase setRightsElement(Text text) {
  		rights = text;
  		return this;
  	}
  	
  	public Text setRights(String value) {
  		rights = new Text();
  		rights.setValue(value);
  		rights.textType = 'text';
  		rights.tagName = 'rights';
  		return rights;
  	}

  /**
   * Sets the value of the rights as @type="html". Special characters like & will be automatically escaped
   * @param value The text value of the atom:rights element.
   * @return The newly created atom:rights element
   */
  	public Text setRightsAsHtml(String value) {
  		rights = setRights(value);
  		rights.setValue(EncodingUtil.urlEncode(value, 'UTF-8'));
  		rights.textType = 'html';
  		rights.tagName = 'rights';
  		return rights;
  	}
  
  /**
   * Sets the value of the rights as @type="xhtml"
   * @param value The text value of the atom:rights element
   * @return The newly created atom:rights element
   */
	public Text setRightsAsXhtml(String value) {
  		rights = setRights(value);
  		rights.setValue(XHTML_DIV + value + XHTML_CLOSE_DIV);
  		rights.textType = 'xhtml';
  		rights.tagName = 'rights';
  		return rights;
  	}
  
  /**
   * Sets the value of the rights
   * @param value The text value of the atom:rights element
   * @param type The text type
   * @return The newly create atom:rights element
   */
  	public Text setRights(String value, String atype) {
  		System.assert(atype == 'text' || atype == 'html' || atype == 'xhtml', '\n\nRights must be type "text", "html" or "xhtml".\n\n');
  		if (atype == 'text') {
  			setRights(value);
  		} else if (atype == 'html') {
  			setRightsAsHtml(value);
  		} else if (atype == 'xhtml') {
  			setRightsAsXhtml(value);
  		}
  		return rights;
  	}
  
  /**
   * Sets the value of the right as @type="xhtml"
   * @param value The XHTML div for the atom:rights element
   * @return The newly created atom:rights element
   */
  //Text setRights(Div value);

  /**
   * Return the String value of the atom:rights element
   * @return The text value of the atom:rights element
   */
  	public String getRights() {
  		if (rights != null) {
	  		return rights.value;
  		} else {
  			return null;
  		}
  	}
  
  /**
   * Return the @type of the atom:rights element
   * @return The Text.Type of the atom:rights element
   */
  	public String getRightsType() {
  		if (rights != null) {
	  		return rights.getTextType();
  		} else {
  			return null;
  		}
  	}
  
  /**
   * <p>Returns the source element for this entry.</p>
   * 
   * <p>RFC4287: If an atom:entry is copied from one feed into another feed, 
   * then the source atom:feed's metadata (all child elements of atom:feed 
   * other than the atom:entry elements) MAY be preserved within the copied
   * entry by adding an atom:source child element, if it is not already
   * present in the entry, and including some or all of the source feed's
   * Metadata elements as the atom:source element's children.  Such
   * metadata SHOULD be preserved if the source atom:feed contains any of
   * the child elements atom:author, atom:contributor, atom:rights, or
   * atom:category and those child elements are not present in the source
   * atom:entry.</p>
   * 
   * @return The atom:source element
   */
  	public Source getSource() {
  		return source;
  	}

	public String getSourceElement() {
		String out = '';
		if (source != null) {
			out += source.ToAPP();
		}
		return out;
	}
	
  /**
   * <p>Returns the source element for this entry.</p>
   * 
   * <p>RFC4287: If an atom:entry is copied from one feed into another feed, 
   * then the source atom:feed's metadata (all child elements of atom:feed 
   * other than the atom:entry elements) MAY be preserved within the copied
   * entry by adding an atom:source child element, if it is not already
   * present in the entry, and including some or all of the source feed's
   * Metadata elements as the atom:source element's children.  Such
   * metadata SHOULD be preserved if the source atom:feed contains any of
   * the child elements atom:author, atom:contributor, atom:rights, or
   * atom:category and those child elements are not present in the source
   * atom:entry.</p>
   * 
   * @param source The atom:source element
   */
  	public AtomBase setSource(Source source) {
  		this.source = source;
  		return this;
  	}
  
  /**
   * RFC4287: The "atom:summary" element is a Text construct that conveys 
   * a short summary, abstract, or excerpt of an entry... It is not advisable 
   * for the atom:summary element to duplicate atom:title or atom:content 
   * because Atom Processors might assume there is a useful summary when there 
   * is none.
   * 
   * @return The atom:summary element
   */
  	public String getSummaryElement() {
  		return summary != null ? summary.ToAPP() : '';
  	}

  /**
   * RFC4287: The "atom:summary" element is a Text construct that conveys 
   * a short summary, abstract, or excerpt of an entry... It is not advisable 
   * for the atom:summary element to duplicate atom:title or atom:content 
   * because Atom Processors might assume there is a useful summary when there 
   * is none.
   * 
   * @param text The atom:summary element
   */
  	public AtomBase setSummaryElement(Text text) {
  		summary = text;
  		return this;
  	}
  
  /**
   * Sets the value of the summary as @type="text"
   * 
   * @param value The text value of the atom:summary element
   * @return the newly created atom:summary element
   */
  	public Text setSummary(String value) {
  		if (summary == null) {
  			summary = new Text();
  		}
  		summary.setValue(value);
  		summary.setTextType('text');
  		summary.setTagName('summary');
  		return summary;
  	}

  /**
   * Sets the value of the summary as @type="html"
   * @param value The text value of the atom:summary element
   * @return the newly created atom:summary element
   */
  	public Text setSummaryAsHtml(String value) {
  		summary = new Text();
  		summary.setValue(EncodingUtil.urlEncode(value, 'UTF-8'));
  		summary.setTextType('html');
  		summary.setTagName('summary');
  		return summary;
  	}
  
  /**
   * Sets the value of the summary as @type="xhtml"
   * @param value The text value of the atom:summary element
   * @return the newly created atom:summary element
   */
  	public Text setSummaryAsXhtml(String value){
  		summary = new Text();
  		summary.setValue(XHTML_DIV + value + XHTML_CLOSE_DIV);
  		summary.setTextType('xhtml');
  		summary.setTagName('summary');
  		return summary;
  	}
  
  /**
   * Sets the value of the summary
   * @param value The text value of the atom:summary element
   * @param type The Text.Type of the atom:summary element
   * @return The newly created atom:summary element
   */
  	public Text setSummary(String value, String atype){
  		System.assert(atype == 'text' || atype == 'html' || atype == 'xhtml', '\n\nSummary must be type "text", "html" or "xhtml".\n\n');
   		if (atype == 'text') {
  			setSummary(value);
  		} else if (atype == 'html') {
  			setSummaryAsHtml(value);
  		} else if (atype == 'xhtml') {
  			setSummaryAsXhtml(value);
  		}
  		return summary;
  	}
  
  /**
   * Sets the value of the summary as @type="xhtml"
   * @param value The XHTML div
   * @return the newly created atom:summary element
   */
  //Text setSummary(Div value);
  
  /**
   * Returns the text string value of this summary
   * @return the text value of the atom:summary
   */
  	public String getSummary() {
  		if (summary != null) {
	  		return summary.getValue();
  		} else {
  			return null;
  		}
  	}
  
  /**
   * Returns the summary type
   * @return the Text.Type of the atom:summary
   */
  	public String getSummaryType() {
  		if (summary != null) {
  			return summary.getTextType();
  		} else {
  			return null;
  		}
  	}
  
  /**
   * RFC4287: The "atom:title" element is a Text construct that conveys a 
   * human-readable title for an entry or feed.
   * @return the atom:title element
   */
  	public String getTitleElement() {
  		return title != null ? title.ToAPP() : '';
  	}

  /**
   * RFC4287: The "atom:title" element is a Text construct that conveys a 
   * human-readable title for an entry or feed.
   * @param title the atom:title element
   */
  	public AtomBase setTitleElement(Text title) {
  		this.title = title;
  		return this;
  	}
  
  /**
   * Sets the value of the title as @type="text"
   * @param value The title value
   * @return The newly created atom:title element
   */
  	public Text setTitle(String value) {
  		title = new Text();
  		title.setValue(value);
  		title.setTextType('text');
  		title.setTagName('title');
  		return title;
  	}
  
  /**
   * Sets the value of the title as @type="html"
   * @param value The title value
   * @return The newly created atom:title element
   */
  	public Text setTitleAsHtml(String value){
  		title = new Text();
  		title.setValue(EncodingUtil.urlEncode(value, 'UTF-8'));
  		title.setTextType('html');
  		title.setTagName('title');
  		return title;
  	}
  
  /**
   * Sets the value of the title as @type="xhtml"
   * @param value The title value
   * @return The newly created atom:title element
   */
  	public Text setTitleAsXhtml(String value){
  		title = new Text();
  		title.setValue(XHTML_DIV + value + XHTML_CLOSE_DIV);
  		title.setTextType('xhtml');
  		title.setTagName('title');
  		return title;
  	}
  
  /**
   * Sets the value of the title
   * @param value The title value
   * @param type The Text.Type of the title
   * @return the newly created atom:title element
   */
  	public Text setTitle(String value, String atype){
  		System.assert(atype == 'text' || atype == 'html' || atype == 'xhtml', '\n\nTitle must be type "text", "html" or "xhtml".\n\n');
   		if (atype == 'text') {
  			setTitle(value);
  		} else if (atype == 'html') {
  			setTitleAsHtml(value);
  		} else if (atype == 'xhtml') {
  			setTitleAsXhtml(value);
  		}
  		return title;
  	}
  
  /**
   * Sets the value of the title as @type="xhtml"
   * @param value The XHTML div
   * @return the newly created atom:title element
   */
  //Text setTitle(Div value);
  
  /**
   * Returns the text string value of the title element
   * @return text value of the atom:title
   */
  	public String getTitle() {
  		if (title != null) {
  			return title.getValue();
  		} else {
  			return null;
  		}
  	}
  
  /**
   * Returns the @type of this entries title
   * @return the Text.Type of the atom:title
   */
  	public String getTitleType() {
  		return title.getTextType();
  	}
  
  /**
   * RFC4287: The "atom:updated" element is a Date construct indicating 
   * the most recent instant in time when an entry or feed was modified 
   * in a way the publisher considers significant.  Therefore, not all
   * modifications necessarily result in a changed atom:updated value.
   * @return the atom:updated element
   */
  	public String getUpdatedElement() {
		return '<updated>' + updated.getAtomString() + '</updated>';
  	}

  /**
   * RFC4287: The "atom:updated" element is a Date construct indicating 
   * the most recent instant in time when an entry or feed was modified 
   * in a way the publisher considers significant.  Therefore, not all
   * modifications necessarily result in a changed atom:updated value.
   * @param updated the atom:updated element.
   */
  	public AtomBase setUpdatedElement(DateTime updated) {
  		this.updated = new AtomDateTime(updated);
  		return this;
  	}
  
  /**
   * Return atom:updated
   * @return A java.util.Date value
   */
  	public AtomDateTime getUpdated() {
  		return updated;
  	}
  
  /**
   * Set the atom:updated value
   * @param value The new value
   * @return The newly created atom:updated element
   */
  	public AtomDateTime setUpdated(Datetime value) {
  		updated = new AtomDateTime(value);
  		return updated;
  	}
  	
  /**
   * Set the atom:updated value
   * @param value The new value
   * @return The newly created atom:updated element
   */
  	public AtomDateTime setUpdated(String value) {
  		updated = new AtomDateTime(value);
  		return updated;
  	}
  	
  	public void setUpdated(AtomDateTime value) {
  		updated = value;
  	}
  
  /**
   * APP Introduces a new app:edited element whose value changes 
   * every time the entry is updated
   * @return the app:edited element
   */
  	public String getEditedElement() {
		return '<app:edited>' + updated.getAtomString() + '</app:edited>';
  	}
  
  /**
   * Set the app:edited element
   * @param modified The app:edited element
   */
   	public AtomDateTime setEditedElement(DateTime modified) {
   		updated = new AtomDateTime(modified);
   		return updated;
   	}
  
  /**
   * Return the value of app:edited
   * @return app:edited
   */
  	public AtomDateTime getEdited() {
  		return edited;
  	}
  
  /**
   * Set the value of app:edited
   * @param value The java.util.Date value
   * @return The newly created app:edited element
   */
  	public AtomDateTime setEdited(Datetime value) {
  		edited = new AtomDateTime(value);
  		return edited;
  	}
  
  /**
   * Set the value of app:edited
   * @param value the serialized string value for app:edited
   * @return The newly created app:edited element
   */
  	public AtomDateTime setEdited(String value) {
  		edited = new AtomDateTime(value);
  		return edited;
  	}
  
  	public void setEdited(AtomDateTime value) {
  		edited = value;
  	}
  	
  /**
   * Returns this entries Atom Publishing Protocol control element.
   * A new control element will be created if one currently does not exist
   * @return The app:control element
   */
  //Control getControl(boolean create);
  
  /**
   * Returns this entries Atom Publishing Protocol control element
   * @return The app:control element
   */
  //Control getControl();
  
  /**
   * Sets this entries Atom Publishing Protocol control element
   * @param control The app:contorl element
   */
  //Entry setControl(Control control);
  
  /**
   * Sets whether or not this entry is a draft
   * @param draft true if this entry should be marked as a draft
   */
	public AtomBase setIsDraft(boolean draft) {
		isDraft = draft;
		return this;
	}
  
  /**
   * Returns true if this entry is a draft
   * @return True if this entry is a date
   */
  	public Boolean getIsDraft() {
  		return isDraft;
  	}
  	public String getIsDraftElement() {
  		String out = '';
  		if (isDraft != null) {
  			out += '<isDraft>' + (isDraft ? 'true': 'false') + '</isDraft>';
  		}
  		return out;
  	}
  	
  	public List<Link> getAlternateLinks() {
  		return getLinks('alternate');
  	}
  /**
   * Returns the first link with the specified rel attribute value
   * @param rel The link rel
   * @return a Link with the specified rel attribute
   */
  	public Link getLink(String rel) {
  		for (Link l : link) {
  			if (l.rel == rel) {
  				return l;
  			}
  		}
  		return null;
  	}
  
  /**
   * Returns this entries first alternate link
   * @return the Alternate link
   */
  	public Link getAlternateLink() {
  		List<Link> links = getAlternateLinks();
  		if (links.size() > 0) {
  			return links[0];
  		}
  		return null;
  	}
  
  /**
   * Returns the first alternate link matching the specified type and hreflang
   * @throws MimeTypeParseException 
   * @param type The link media type
   * @param hreflang The link target language
   * @return The matching atom:link
   * @throws MimeTypeParseException if the type is malformed
   */
  	public Link getAlternateLink(String atype, String hreflang) {
  		List<Link> links = getAlternateLinks();
  		for (Link l : links) {
  			if (l.ltype == atype && l.hreflang == hreflang) {
  				return l;
  			}
  		}
  		return null;
  	}
  
  	public List<Link> getEnclosureLinks() {
  		return getLinks('enclosure');
  	}
  /**
   * Returns this entries first enclosure link
   * @return the Enclosure link
   */
  	public Link getEnclosureLink() {
  		List<Link> enclosures = getEnclosureLinks();
  		if (enclosures.size() > 0) {
  			return enclosures[0];
  		}
  		return null;
  	}
  
  	public List<Link> getEditLinks() {
  		return getLinks('edit');
  	}
  /**
   * Returns this entries first edit link
   * @return the Edit Link
   */
  	public Link getEditLink() {
  		List<Link> edits = getEditLinks();
  		if (edits.size() > 0) {
  			return edits[0];
  		}
  		return null;
  	}
  
  /**
   * Returns this entries first edit-media link (if any)
   * @return the Edit Media Link
   */
  	public Link getEditMediaLink() {
  		List<Link> edits = getLinks('edit-media');
  		if (edits.size() > 0) {
  			return edits[0];
  		}
  		return null;
  	}
  
  /**
   * Returns the first edit-media link matching the specified type and hreflang
   * @param type a media type
   * @param hreflang a target language
   * @return A matching atom:link element
   * @throws MimeTypeParseException 
   */
  	public Link getEditMediaLink(String atype, String hreflang) {
  		List<Link> edits = getLinks('edit-media');
  		for (Link l : edits) {
  			if (l.ltype == atype && l.hreflang == hreflang) {
  				return l;
  			}
  		}
  		return null;
  	}
  
  /**
   * Returns this entries first self link
   * @return the Self Link
   */
  	public Link getSelfLink() {
  		List<Link> selfs = getLinks('self');
  		if (selfs.size() > 0) {
  			return selfs[0];
  		}
  		return null;
  	}
 
  /**
   * Return a link href resolved against the in-scope Base URI
   * @param rel The rel attribute value
   * @return The resolved IRI
   * @throws IRISyntaxException if the href attribute is malformed
   */
  //IRI getLinkResolvedHref(String rel) ;

  /**
   * Return a link href resolved against the in-scope Base URI
   * @return The resolved IRI
   * @throws IRISyntaxException if the href attribute is malformed
   */
  //IRI getAlternateLinkResolvedHref() ;

  /**
   * Return a link href resolved against the in-scope Base URI
   * @param type A target type
   * @param hreflang A target language
   * @return The resolved IRI
   * @throws IRISyntaxException if the href attribute is malformed
   */
  //IRI getAlternateLinkResolvedHref(String atype, String hreflang);

  /**
   * Return a link href resolved against the in-scope Base URI
   * @return The resolved IRI
   * @throws IRISyntaxException if the href attribute is malformed
   */
  //IRI getEnclosureLinkResolvedHref() ;

  /**
   * Return a link href resolved against the in-scope Base URI
   * @return The resolved IRI
   * @throws IRISyntaxException if the href attribute is malformed
   */
  //IRI getEditLinkResolvedHref() ;

  /**
   * Return a link href resolved against the in-scope Base URI
   * @return The resolved IRI
   * @throws IRISyntaxException if the href attribute is malformed
   */
  //IRI getEditMediaLinkResolvedHref() ;

  /**
   * Return a link href resolved against the in-scope Base URI
   * @param type A target type
   * @param hreflang A target language
   * @return The resolved IRI
   * @throws IRISyntaxException if the href attribute is malformed
   * @throws MimeTypeParseException if the type is malformed
   */
  //IRI getEditMediaLinkResolvedHref(String atype, String hreflang);
 
  /**
   * Return a link href resolved against the in-scope Base URI
   * @return The resolved IRI
   * @throws IRISyntaxException if the href attribute is malformed
   */
  //IRI getSelfLinkResolvedHref();
  
  //Control addControl();

}